#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#include <string>
#include <unordered_map>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <iostream>
#include <unistd.h>
#include <string>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <functional>
using namespace std;
#define DEBUG 0
#define NOTICE 1
#define WARINING 2
#define FATAL 3

#define SOCKET_ERR 1
#define BIND_ERR 2
#define LISTEN_ERR 3
#define USAGE_ERR 4
#define CONN_ERR 5

#define BUFFER_SIZE 1024

void handlerHttpRequest(int serviceSock, string &ip, uint16_t peerPort)
{
    char buff[BUFFER_SIZE * 10];
    ssize_t s = read(serviceSock, buff, sizeof buff);
    if (s > 0)
        cout << buff << endl;
}

class tcpServer
{
public:
    tcpServer(uint16_t port, string ip)
        : port_(port), ip_(ip), listenSock_(-1)
    {
    }
    ~tcpServer() {}

    void init()
    {
        // 1.创建套接字
        listenSock_ = socket(AF_INET, SOCK_STREAM, 0);
        if (listenSock_ < 0)
        {
            exit(SOCKET_ERR);
        }
        // 2. bind
        // 2.1 填充信息到结构体
        struct sockaddr_in local;
        memset(&local, 0, sizeof local);
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        ip_.empty() ? (local.sin_addr.s_addr = INADDR_ANY) : (inet_aton(ip_.c_str(), &local.sin_addr));
        // 2.2 bind,本地sock写入内核sock
        if (bind(listenSock_, (const struct sockaddr *)&local, sizeof(local)) < 0)
        {
            exit(BIND_ERR);
        }

        // 3.监听
        if (listen(listenSock_, 5) < 0)
        {
            exit(LISTEN_ERR);
        }
    }

    void start()
    {
        while (1)
        {
            // signal(SIGCHLD,SIG_IGN);
            //  4.连接
            struct sockaddr_in peer;
            socklen_t len = sizeof peer;
            int serviceSock = accept(listenSock_, (struct sockaddr *)&peer, &len);
            if (serviceSock < 0)
            {
                continue;
            }
            // 4.1获取客户端基本信息
            uint16_t peerPort = ntohs(peer.sin_port);
            string ip = inet_ntoa(peer.sin_addr);
            // 多进程版本  创建孙子进程，退出父进程，让系统回收孤儿进程
            pid_t id = fork();
            assert(id != -1);
            if (id == 0)
            {
                close(listenSock_);
                if (fork() > 0)
                    exit(0);
                // 孙子进程提供服务
                handlerHttpRequest(serviceSock, ip, peerPort);
                exit(0);
            }
            pid_t ret = waitpid(id, nullptr, 0);
            assert(ret > 0);
            (void)ret;
        }
    }

private:
    int listenSock_; // 监听套接字
    uint16_t port_;  // 端口号
    string ip_;      // ip地址
};
int main(int argc, char *argv[])
{
    if (argc != 2 && argc != 3)
    {
        cout << "Usage:\n\t" << argv[0] << " port [ip]" << endl;
        exit(USAGE_ERR);
    }
    uint16_t port = atoi(argv[1]);
    string ip;
    if (argc == 3)
        ip = argv[2];

    tcpServer ts(port, ip);
    ts.init();
    ts.start();
    return 0;
}
